using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Web.UI;
using System.Web.UI.WebControls;
using OpenWaves.ImageTransformations;
using OpenWaves.Web.ImageTransformations;

namespace OpenWaves.Web.Controls
{
    public abstract class ImageBase : ExpandoControl
    {
        public string ImageUrl
        {
            get { return (string)this.ViewState["ImageUrl"] ?? string.Empty; }
            set { this.ViewState["ImageUrl"] = value; }
        }

        public string FallbackImageUrl
        {
            get { return (string)this.ViewState["FallbackImageUrl"] ?? string.Empty; }
            set { this.ViewState["FallbackImageUrl"] = value; }
        }

        public string CssClass
        {
            get { return (string)this.ViewState["CssClass"] ?? string.Empty; }
            set { this.ViewState["CssClass"] = value; }
        }

        [Obsolete("Use ToolTip instead", true)]
        public string Title
        {
            get { return this.ToolTip; }
            set { this.ToolTip = value; }
        }

        public bool HideIfEmpty
        {
            get { return (bool)(this.ViewState["HideIfEmpty"] ?? false); }
            set { this.ViewState["HideIfEmpty"] = value; }
        }

        public string ToolTip
        {
            get { return (string)this.ViewState["ToolTip"] ?? string.Empty; }
            set { this.ViewState["ToolTip"] = value; }
        }

        [Obsolete("Use AlternateText instead", true)]
        public string Alt
        {
            get { return this.ToolTip; }
            set { this.ToolTip = value; }
        }

        public string AlternateText
        {
            get { return (string)this.ViewState["AlternateText"] ?? string.Empty; }
            set { this.ViewState["AlternateText"] = value; }            
        }

        public ImageTransformationType Transformation
        {
            get { return (ImageTransformationType)(this.ViewState["Transformation"] ?? ImageTransformationType.None); }
            set { this.ViewState["Transformation"] = value; }
        }

        public string CustomTransformation
        {
            get { return (string)(this.ViewState["CustomTransformation"] ?? String.Empty); }
            set { this.ViewState["CustomTransformation"] = value; }
        }

        public event EventHandler<ImageTransformationFailedEventArgs> ImageTransformationFailed;

        protected virtual void OnImageTransformationFailed(ImageTransformationFailedEventArgs args)
        {
            if (this.ImageTransformationFailed != null)
                this.ImageTransformationFailed(this, args);
        }

        protected virtual void LogImageTransformationFailure(ImageTransformationException reason)
        {
            Log.Warning("{0}: Image was not resolved for ImageUrl='{1}'. {2}.", this.UniqueID, this.ImageUrl, reason);
        }

        protected virtual string GetTransformedImageUrl(string sourceImageUrl, IImageTransformation transformation)
        {
            Contract.Requires(String.IsNullOrEmpty(sourceImageUrl) == false);

            Url imageUrl;
            if (Url.TryParse(sourceImageUrl, out imageUrl) == false)
                Contract.Assert(false, this.FormatExceptionMessage("Failed to parse sourceImageUrl: '{0}'", sourceImageUrl));

            var imageTransformationService = ServiceLocator.Resolve<IWebImageTransformationService>();
            var transformedImageUrl = imageTransformationService.GetTransformedImageUrl(imageUrl, transformation);

            return this.ResolveImageUrl(transformedImageUrl.ToString());
        }

        private string FormatExceptionMessage(string format, params object[] args)
        {
            return this.UniqueID + ": " + ExceptionMessage.Format(format, args);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                if (String.IsNullOrEmpty(this.ImageUrl) == false)
                {
                    this.RenderImage(this.ImageUrl, writer);
                    return;
                }
                
                if (this.HideIfEmpty)
                    return;

                if (String.IsNullOrEmpty(this.FallbackImageUrl) == false)
                {
                    this.RenderImage(this.FallbackImageUrl, writer);
                    return;
                }

                this.RenderImage(String.Empty, writer);
            }
            catch (ImageTransformationException ex)
            {
                var args = new ImageTransformationFailedEventArgs(ex)
                    {
                        FallbackImageUrl = this.FallbackImageUrl,
                        LogError = true
                    };

                this.OnImageTransformationFailed(args);

                if (args.LogError)
                    this.LogImageTransformationFailure(ex);

                if (String.IsNullOrEmpty(args.FallbackImageUrl) && this.HideIfEmpty)
                    return;
                    
                this.RenderImage(args.FallbackImageUrl, writer);
            }
        }

        protected abstract void RenderImage(string imageUrl, HtmlTextWriter writer);

        protected void RenderImageTag(string imageUrl, ImageTransformationType transformationType, string customTransformationType, int width, int height, HtmlTextWriter writer)
        {
            this.AddAttributesToRender(writer);

            if (String.IsNullOrEmpty(imageUrl) == false)
            {
                var transformation = transformationType.CreateImageTransformation(customTransformationType, width, height);

                if (transformation == null || Equals(transformation, ImageTransformation.Null))
                {
                    writer.AddAttribute(HtmlTextWriterAttribute.Src, this.ResolveImageUrl(imageUrl));
                }
                else
                {
                    writer.AddAttribute(HtmlTextWriterAttribute.Src, this.GetTransformedImageUrl(imageUrl, transformation));
                }
            }

            if (String.IsNullOrEmpty(this.CssClass) == false)
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);

            // alt attribute required according to w3c
            writer.AddAttribute(HtmlTextWriterAttribute.Alt, this.AlternateText ?? string.Empty);

            if (String.IsNullOrEmpty(this.ToolTip) == false)
                writer.AddAttribute(HtmlTextWriterAttribute.Title, this.ToolTip);

            writer.RenderBeginTag(HtmlTextWriterTag.Img);
            writer.RenderEndTag();
        }

        protected virtual string ResolveImageUrl(string url)
        {
            return this.ResolveUrl(url);
        }
    }
}